import fs from "fs";
import EventEmitter from "events";
class ReadStream extends EventEmitter {
  constructor(path, options) {
    super();
    this.path = path; // fs.open()
    this.flags = options.flags || "r";

    this.highWaterMark = options.highWaterMark || 64 * 1024;
    this.emitClose = options.emitClose || true;

    this.start = options.start || 0;
    this.end = options.end; // 默认读取的位置 从哪个地方开始到哪里

    this.flowing = false;
    this.fd = null;
    this.offset = 0; // 每次读取的偏移量
    this.open();
    this.on("newListener", (eventName) => {
      if (eventName == "data") {
        this.flowing = true; // 开始读取
        this.read();
      }
    });
  }
  pause(){
    this.flowing = false;
  }
  resume(){
    if(this.flowing === false){
        this.flowing = true;
        this.read();
    }
  }
  destroy(err) {
    if(typeof this.fd === 'number'){
        fs.close(this.fd,()=>this.emit('close'))
    }
    if (err) {
      this.emit("error", err);
    }
  }
  open() {
    fs.open(this.path, this.flags, (err, fd) => {
      if (err) {
        return this.destroy(err);
      }
      this.fd = fd; // 文件打开后 会有fd属性
      this.emit("open", fd);
    });
  }
  read() {
    if (typeof this.fd !== "number") {
      // 这里的目的是将读取的操作延迟到 open之后
      return this.once("open", () => this.read());
    }
    // 保证读取发射出去的数据 都是一个新的空间，用户收集的时候是不同的内存
    const buffer = Buffer.alloc(this.highWaterMark);

    // 0 - 10  11个字节   4  4  3

    // 计算最后一次是否需要读的更少
     const howMuchToRead = this.end ?  Math.min(this.end - this.offset + 1,this.highWaterMark) : this.highWaterMark

    fs.read(this.fd, buffer,0,howMuchToRead,this.offset,(err,bytesRead)=>{
        if(err){
            return this.destroy(err);
        }
        if(bytesRead == 0){
            this.emit('end');
            this.destroy();
        }else{
            this.offset += bytesRead;
            this.emit('data',buffer.subarray(0,bytesRead))

            if(this.flowing){
                this.read()
            }

        }
    });
  }
}

function createReadStream(path, options = {}) {
  return new ReadStream(path, options);
}

export { createReadStream };
